|
Вы пришли из
Браузер у вас:
Сегодня:
Разрешение монитора:
Учебники по программированию DCOM или Компоненты Клиент-Сервер
Хочу поделится
собственным опытом написания, и
главное настройки чуда, названного
Микрософтом DCOM (Распределенные
Компоненты - перевод вольный). Идея
здравая и заключается она в том, что
ваша Visual Basic программа может иметь
удаленные компоненты. Здесь и далее
под компонентами понимается
приложение имеющее внутри обьект
или обьекты , которые могут быть
созданы и использованы
"Извне". Если вы знакомитесь с
обьектным Бэйсиком только сейчас -
то компоненты легко создаются если
вы выберете пункт ActiveX EXE или ActiveX DLL
при старте среды Бэйсика. Но я
отвлекся, Эти самые компоненты
могут находится на вашем
компьютере, и тогда никакой DCOM вам
не нужен. Однако могут они лежать и
на другой, доступной по сети машине.
В этом случае удаленная компонента
будет выполняться на той машине - на
которой она лежит. Называться
такакя компонента будет Сервером.
Вот об этой то ситуации мы и
поговорим. В самом деле Микрософт в
Books-Online достаточно подробно говорит
о создании компонентов, и даже
приводит примеры. Рекомендую
глянуть . Проблема только в том , что
абсолютно не описана установка и
настройка для правильной и
надежной работы.
Итак, задача:
Существует приложение, запускаемое
с разных компьютеров (Multiuse Mode)и
обращающающееся к базе данных
расположенной на сервере. База
данных - стандартная *.mdb .
Необходимо внедрить в эту
программу возможность контроля за
количеством одновременно
используемых копий программ,
подсоединненных к серверу (Licence
Control) , причем две или три копии
программы запущенные одновременно
на одном компьютере "съедают"
только одну лицензию.
Выбрана следующая
схема решения этой задачи:
Создается удаленная компонента,
которая которая устанавливается на
сервере, Инстанс (э-э-э, пожалуй это
можно перевести как одна
запущенная копия) этой компоненты
будет создаваться всякий раз при
старте основного приложения на
любой из клиентских машин. И будет
хранить информацию о текущих
подсоединенных к базе именах
компьютеров. После выгрузки
последней копии клиентской
программы компонента тоже
выгрузится из памяти сервера
(неплохо, правда?).
Как это реализованно. Компонента создается как ActiveX.EXE
приложение, и в свойствах проекта (Закладка Component) сразу устанавливаем галочку,
указывающую что это будет Remote Server, ActiveX Component и Binary Compatibility.
Последнее совсем не помешает вам, когда вы будете устанавливать на сервере свою
компоненту, тестировать, пересоздавать, и снова устанавливать. О создании несовместимой
версии вас предупредят при компиляции - и это значит надо удалить все ссылки
о старой версии, и зарегистрировать новую, но об этом чуть ниже. (Закладка General)
- тут вы должны написать Project Name & Project Description. Startup Object
- Sub Main. Поставьте галочку на Upgrade ActiveX Component и выбрерите Tread
Pool = 1
На этом настройку
проекта компоненты можно считать
законченой . Сама компонента
состоит из 2-х классов, Первый из
которых (RLHolder) является
"хранилищем" созданных
коннектов (этот класс создается
только изнутри компоненты, и
количество его инстансов всегда не
больше 1) В связи с этим свойство
Instancing смело устанавливаем в Private.
Сам по себе класс содержит одну
коллекцию , в которую и
добавляются-убавляются коннекты с
приложением. Сами по себе коннекты
выглядят как просто число типа
Целое, от 1 и более, означающее
количество копий запущеной на
конкретном компьютере программы.
Имя этого компьютера выступает в
качестве "ключа" элемента
коллекции. Методы и Свойства этого
класса позволяют обращатся к
указанной коллекции, добавлять,
убавлять, считать коннекты.
Второй класс (RLMain)
должен быть доступным для создания
"извне" т.е. с удаленной машины.
Его Instancing - Multiuse (возможность
работать с одной копией сервера
многим клиентам),
Так же в проекте есть
модуль , в котором есть пустая
процедура Sub Main, и Public переменная
типа RLHolder. Инстанс первого класса
создается при рождении второго - на
событие Class_Initialize. Создается не
просто так , а с проверкой - если
переменная обьявленная в модуле
уже ссылается на инстанс класса, то
ничего не происходит, если нет - то
создается новая, и таким образом
единственная, инстанс.
Второй класс так же
как и первый содержит методы и
свойства - пересчитывающие ,
добавляющие и убивающие коннекты.
Эти методы и свойства просто
вызывают аналогичные методы и
свойства первого класса.
Остановимся на этом - вы можете скачать пример,
и посмотреть все своими глазами. А вероятнее всего вы это все знаете и без меня.
Перейдем к более интересному.
Микрософт уверяет, что достаточно создать сетап-визардом
простой сетап, указав , что компонента будет shared, и на сервере все само настроится.
Частично он как всегда прав. Начнем с сети - если вы еще не установили TCP/IP
протокол, то самое время сделать это. Этот протокол ДОЛЖЕН корректно работать
на всех машинах которые будут использовать DCOM. Неплохо временно убить остальные
протоколы, чтобы удостоверится в работоспособности TCP/IP. Далее - Если вы ставите
эту удаленную компоненту на NT (а под Вин95 ее не рекомендуют ставить, хотя
и должно работать) то для установки достаточно создать указанный сетап и выполнить
его на NT машине. При последующих сменах версии вам необходимо обновлять сам
*.exe файл , а также одноименные файлы с раширениями .tlb .vbr Если вы воспользовались
сетапом , то все это будет лежать в system32 дирректории вашей NT. После этого
разыщите в этой же директории файл dcomcnfg.exe и запустите его. В списке Application
найдите свою компоненту - нам нужно поменять некоторые свойства - Закладка Location
- поставить галочку на "Run App on this computer", Закладка Identity
- выберите Interactive User. По умолчанию установленно другое свойство, и при
запуске на каждого юзера будет создаваться своя копия компоненты в памяти (Инстанс)
Т.е. мы потеряем то, к чему стремились - единая компонента, обслуживающая ВСЕХ
пользователей. Закладку Security поправить просто - добавьте всюду EveryOne
со всеми правами, и дело с концом. Жмем Apply и считаем настройку сервера выполненой.
На будущее - не вредно заглянуть в vbr файл, там лежат ключи в регистри, которые
описывают компоненту. Нередко после 3-4-5 обновлений, с нарушением cовместимости
версий надо почистить реестр от всех этих ключей, и просто один раз запустить
*.exe с компонентой. почистить реестр можно как ручками, так и с запуском утилиты
regsvr32.exe с ключем /u
(В этом месте меня поправил Igor Martynenko, и
он абсолютно прав)
Согласно документации Microsoft для регистрации
ActiveX EXE необходимо либо запустить этот самый сервер и он сам зарегистрируется,
либо запустить сервер с параметром /RegServer, т.е.
, MySvr.EXE /RegServer
Для разрегистрации сервера необходимо использовать параметр /UnRegServer соответственно,
т.е MySvr.EXE /UnRegServer
Запуск regsvr32.exe с ключем /u помогает для разрегистрации
*.dll
Работу с DCOM на
клиентской машине надо начать с....
:-) установки DCOM на этой машине.
Взять его можно на дистрибутивном
диске Visual Basic 5, или на сайте у
Микрософта. Этот файлик занимает
чуть более одного мегабайта и
является самоустанавливающимся
архивом.(DCOM95.EXE) Если будут желающие,
я выложу его на страничку. Не
забывайте устанавливать его и на
машите у покупателей вашей
программы, без этого DCOM там не будет
работать тоже - естественно, одной
инсталяции достаточно до
переустановки виндов. Инсталяция
DCOM входит в поставку Windows NT, так что
на ней об этом можно не беспкоится.
К слову, я пробовал устанавливать
DCOM98 (на машину где стоял пятый
Бэйсик, и куча разного софта) и DCOM
после этого не работал напрочь -
вис, пришлось все вернуть назад, и
поставить DCOM95. При том, что на рядом
стоящей чистой машине с
установленным VB6 он работает
отлично.
По поводу клиента - эта программа
должна делать собственно пару
вещей - первое, создавать инстанс
класса RLMain , передавать сведения об
имени компьютера, на котором
выполняется, запрашивать разрешено
ли коннектится к серверу, и если да -
то просто молча уступить дорогу
основной программе. Клиентская
часть у меня в примере оформлена
как отдельная тестовая програмка, в
самом деле она будет встроена в
основной проект и предварять
процедуру логона в систему.
Соотвественно на выходе из
программы нужно проверить запущена
ли хотя бы одна копия этой
программы, и если да - то просто
уменьшить счетчик - определяющий
сколько коннектов сделано с этого
компьютера, если нет - то совсем
убить коннекшн и этим освободить
одну лицензию.
Как это реализовано - первая сложность с которой вы
можете столкнуться - это обьявление типа обьектной переменной. Как вы несомненно
помните, существует два типа "связывания" обьектной переменной с самим
обьектом - "Раннее" и "Позднее" Первое отличается от второго
скоростью выполнения , "Раннее" связывание работает быстрее. Второе
отличие более неприятно в период разработки - Бэйсик не знает о каком обьекте
идет речь и не подсказывает вам свойства и методы этого обьекта после того как
вы ставите точку (а это непривычно и неудобно). Итак, достаточно обьявить
Dim obj as object
set obj = createObject("RLServ.RLMain")
И далее пользоваться пременной OBJ -
как я указывал это второй метод
связывания (Поздний) Почему это
работает медленнее тоже обьяснимо -
встретив в коде строку с просьбой
создать обьект названного типа,
Бэйсик лезет в регистри и ищет там
идентификатор класса с таким
именем, смотрит по этому
идентификатору на что ссылается
обьект (библиотеку типов например)
и только после этого может
приступать к созданию ссылки на
такой обьект. В случае раннего
связывания описанную работу Бэйск
делает во время компиляции, и на
стадии выполнения сразу создает
ссылку. Почему я об этом
рассказываю - вы должы понимать -
что в сущности происходит при
создани обьектов. Тут , пожалуй надо
упомянуть о следующем - Если вы
создаете ActiveX DLL, компилируете его ,
закрываете свой этот проект,
открываете другой - в референсах вы
сразу можете найти ссылку на свою
DLL(там будет стоять то имя, которое
вы написали в Description в свойствах
проекта). Бэйсик регистрирует такие
обьекты при компиляции, так же, как
вы можете сделать это и сами , с
помощью regsvr32.exe. Если же вы создаете
ActiveX ЕХЕ , то ссылки вы не
обнаружите. Ее еще просто нету. Для
созданиия ссылки в Progect-References - надо
зарегистрировать этот *.exe.
Достарочно его один раз запустить ,
и все. Экзекутабл ActiveX являются
саморегистрирующимися обьектами.
Применительно к нашему проекту
делать этого не нужно, более того
крайне вредно. Если вы все- таки
случайно запустили этот *.exe - ничего
срашного - скопируйте в дирректорию
вашего проекта из windows\system файлик
regsvr32.exe и запустите его примерно
так: regsvr32.exe /u MyServerName.exe
Следуя за моими извилистыми
обьяснениями, вы уже поняли, что ваш
удаленный сервер НЕ ДОЛЖЕН быть
зарегистрирован на вашей машине -
но я, конечно, обманул вас - должен.
Только это должна быть регистрация
УДАЛЕННОГО *.exe . Для этого
существует как обычно несколько
путей. Первый - создать визардом
инсталяшку, указав в ней, что вы
используете в проекте удаленный
сервер. Указывать удаленный сервер
, точнее его *.vbr файл надо ручками,
сетап сам не определит наличие его
в проекте. Далее надо выбрать тип
доступа DCOM (реально там надо
ответить NO, потому, что вопрос стоит
использовать Ole Automation или нет - если
нет - то это DCOM), напечатать имя
компьютера, на котором будет
запускаться сервер , и после
создания достаточно выполнить этот
сетап на машине клиента,
регистрация будет произведена. Но,
согласитесь - создавать и ранать
сетап после каждого мало - мальски
серьезеного изменения, пока вы
создаете и отлаживаете программу
несколько занудно, надоедливо и
неэкономчно. Выход уже найден -
программа CliReg32.exe. Она не
поставляется с Windows, но ее можно
найти где-то внутри бэйсиковского
каталога. Не скажу точно, так как у
меня сейчас установлен VB6, а в нем
немного иначе все распологается ,
чем в пятом.
Найдите эту программу, и скопируйте
ее в дирректорию с вашим сервером. В
моем случае строка регистрации
выглядит так
CLIREG32.EXE "rlserv.VBR" /s "ntserver40" /t
"rlserv.TLB" /d /l
Где ntserver40 - зто сетевое имя
компьютера, на котором будет
пускаться сервер rlserv.exe
Назначение и имена ключей можно
посмотреть запустив CLIREG32.EXE /?
Обратите внимание на
неестественный пробел между
ключем, и параметром , который этот
ключ описвает (напримет /s
"ntserver40") Я провозился с этим
добрых полчаса - пока не
распотрошил сетап-визард в
исходнике.
Если вы создаете несовместимый с
прошлой версией сервер , старый
нужно "разрегистрировать"
используя эту же утилиту - только с
ключем "/u". Только не нарушайте
последовательность - получив
предупреждение об несовместимости
версий сервера - откажитесь от
компиляции, разрегистрируйте
сервер, откомпилируйте новую
версию и зарегистрируйте его снова.
После всех этих извращений у нас
уже готов к работе север, компьютер
клиент, и может быть имеется
некоторая ясность как писать
программу клиент. Мы в общем -то
остановились на обьявлении
обьектной переменной. Обявлять ее
просто как object не интересно (хотя и
вполне возможно, и я сам так и делаю
в примере), поэтому дарю вам
хитрость, как обьявить переменную
для "Раннего" связывания.
Первое - вам надо убить все ссылки
на сервер этот EXE сервер как
локальный (regsvr32.exe /u),
зарегистрировать как удаленный (см
выше), пойти в Progect-References , нажать
кнопку Browse, и выбрать *.tlb файл (в
моем случае rlserv.TLB) Именно TLB, не EXE .
После этого имеет право на жизнь
такая строчка
dim obj as New RLServ.RlMain
Еще пару строк о клиенте -
переменная obj обьявляется так,
чтобы время ее жизни равнялось
времени жизни приложения. Почему?
Ну сами уже догадались , из условий
задачи. Все остальные тонкости -
можно уже относить к вашему стилю
программирования и желанинию
навесить на сервер какие-то
дополнительные возможности. У меня,
например, сервер честно возвращает
время на машине сервере по свойству
GetTime, что позволяет не заботится о
синхронизации времени клиентов и
сервера в сети. Так - же мой пример,
до поднятия сервиса проверяет куда
пользователь хочет коннектится,
если он использует локальную
датабэйз , сидящую на его
собственном жестком диске - доступ
происходит без контроля лицензий.
Еще одно интересное свойство этой
технологии - то что оно так же
хорошо должно работать через RAS
(доступ по модему , например).
Кстати, используя эту технологию
можно достачно легко создавать
асинхронный CallBack - т.е. сервер будет
сам дергать клиента при
наступлении опреденных событий.
Причем не всех клиентов сразу - а
только нужного. Я не пробовал
сейчас это делать, да и в комплекте
Бэйсика есть описание и пример по
этому поводу - сходите в BooksOnline.
| |